class VNode {
    constructor(type, attrs, children = []) {
        this.type = type;//节点的类型 div p span
        this.attrs = attrs;//节点的属性 id ,style,class
        this.children = children;//子节点 hello, []
    }
}
var vm = {name:'zhangsan',age:'18'};
//元素节点
const NODE_ELEMENT = 1;
const NODE_TEXT = 3;
function generateRenderFn(node) {
    //如果此节点是一个元素节点的话
    if (node.nodeType === NODE_ELEMENT) {
        //获取此节点的类型名 div
        let type = node.tagName.toLowerCase();
        //先获取节点的类数组，转换成节点的数组进行计算
        //把attributes变成属性对象{id:"app"}
        const attrs = Array.from(node.attributes).reduce((acc, attr) => {
            acc[attr.name] = attr.value;
            return acc;
        }, {});
        //再处理子节点,获取子节点的数组,把每个子节点映射为一个函数
        const children = Array.from(node.childNodes).map(
            childNode => generateRenderFn(childNode));
        return () => {
            const vNode = new VNode(type, attrs, children.map(fn => fn.call(this)));
            return vNode;
        }
    } else if (node.nodeType === NODE_TEXT) {
        let text = node.nodeValue;
        return () => text.replace(/\{\{(.+?)\}\}/g,(_,key)=>{
            return vm[key];
        });
    }
}
//把虚拟DOM变成真实DOM
function createDOMElementFromVnode(vNode) {
    //创建一个类型为vNode.type的真实DOM
    let domElement = document.createElement(vNode.type);
    //给新创建的DOM元素添加属性
    for (const key in vNode.attrs) {
        domElement.setAttribute(key, vNode.attrs[key]);
    }
    //创建儿子的DOM元素并添加到自己身上
    vNode.children.forEach(child => {
        //如果子节点是一个字符串，它创建文本节点
        if (typeof child === 'string') {
            //创建文本节点并添加到父节点上
            let childElement = document.createTextNode(child);
            domElement.appendChild(childElement);
            //如果子节点也是一个虚拟DOM节点的话
        } else if (child instanceof VNode) {
            let childElement = this.createDOMElementFromVnode(child);
            domElement.appendChild(childElement);
        }
    });
    return domElement;
}
//这是模板定义
let el = document.querySelector('#app');
let template = el.outerHTML;
//把模板定义转成一个render函数
//先创建一个DOM解析器
let domParser = new DOMParser();
//把模板内容传递给DOM解析器
let doc = domParser.parseFromString(template, 'text/html');
//得到模板的第一个DOM节点<div id="app">
let rootNode = doc.body.firstChild;
//把根节点传给generateRender生成render函数
let render = generateRenderFn(rootNode);
//执行render函数，可以获取根虚拟DOM节点
let vNode = render();
console.log(vNode)
//创建真实DOM div#app替换掉老的DOM div#app
let domElement = createDOMElementFromVnode(vNode);
//用新创建的真实DOM替换旧掉老的div#app节点。完成了渲染
el.replaceWith(domElement);